﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using MotionCS.Controller;
using MotionCS.Helper;
using MotionCS.Enumerate;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Reflection;
using MotionCS.Config;
using MotionCS.Alarm;
using System.Collections.Concurrent;
using System.Collections;
using MotionCS.StatusLed;

namespace MotionCS.Module
{
    public class ConveyorModule
    {
        #region 模组定义
        /// <summary>
        /// 取像信息
        /// </summary>
        private class GrabInfo
        {
            /// <summary>
            /// 拍照ID
            /// </summary>
            public string GrabUuid;
            /// <summary>
            /// 是否取像结束
            /// </summary>
            public bool IsGrabEnd;
            /// <summary>
            /// 检测ID
            /// </summary>
            public string CheckUuid;
            /// <summary>
            /// 是否NG
            /// </summary>
            public bool IsNg;
        }
        /// <summary>
        /// 产品检测结果
        /// </summary>
        private class ProductResult
        {
            /// <summary>
            /// pcb标识符
            /// </summary>
            public string uuid;
            /// <summary>
            /// 是否NG
            /// </summary>
            public bool isNg;
        }
        /// <summary>
        /// 在线模式状态机
        /// </summary>
        public enum AutoStepE
        {
            /// <summary>
            /// 等待
            /// </summary>
            Wait,
            /// <summary>
            /// 初始
            /// </summary>
            Init,
            /// <summary>
            /// 读码等待
            /// </summary>
            ReadCodeWait,
            /// <summary>
            /// 读码接收
            /// </summary>
            ReadCodeRecv,
            /// <summary>
            /// 读码校验
            /// </summary>
            ReadCodeCheck,
            /// <summary>
            /// 进料等待
            /// </summary>
            InputWait,
            /// <summary>
            /// 进料开始
            /// </summary>
            InputStart,
            /// <summary>
            /// 进料减速
            /// </summary>
            InputDecel,
            /// <summary>
            /// 进料停止
            /// </summary>
            InputStop,
            /// <summary>
            /// 等待SPI取像命令
            /// </summary>
            WaiteGrabCommand,
            /// <summary>
            /// 取像开始
            /// </summary>
            GrabStart,
            /// <summary>
            /// 取像结束
            /// </summary>
            GrabStop,
            /// <summary>
            /// 出板开始
            /// </summary>
            OutputStart,
            /// <summary>
            /// 出板进行
            /// </summary>
            OutputRunning,
            /// <summary>
            /// 出板暂停
            /// </summary>
            OutputPause,
            /// <summary>
            /// 出板等待
            /// </summary>
            OutputWait,
            /// <summary>
            /// 出板停止
            OutputWait2,
            /// <summary>
            /// 出板停止
            /// </summary>
            OutputFinish,
            /// <summary>
            /// 退出
            /// </summary>
            Exit,

            /// <summary>
            /// 上料位置
            /// </summary>
            InPutBoard,

            /// <summary>
            /// 开始退板
            /// </summary>
            ReturnStart
        }
        /// <summary>
        /// 复位枚举
        /// </summary>
        private enum ResetStepE
        {
            /// <summary>
            /// 初始
            /// </summary>
            Init,
            /// <summary>
            /// 皮带反转
            /// </summary>
            BeltBackward,
            /// <summary>
            /// 轨道回零
            /// </summary>
            WidthMoveHome,
            /// <summary>
            /// 等待回零
            /// </summary>
            WidthWaitHome,
            /// <summary>
            /// 轨道回基点
            /// </summary>
            WidthMoveBase,
            /// <summary>
            /// 等待回基点
            /// </summary>
            WidthWaitBase,
            /// <summary>
            /// 完成
            /// </summary>
            Finish
        }
        #endregion
        #region 模组属性
        public string ModuleName { get => config.Name; }
        /// <summary>
        /// 模组键值
        /// </summary>
        public int ModuleKey { get => config.ModuleKey; }
        /// <summary>
        /// 是否启用
        /// </summary>
        public bool isEnable = false;
        public bool IsEnable { get => isEnable; }
        /// <summary>
        /// 是否输出日志
        /// </summary>
        private bool isLogout;
        public bool IsLogOut { get => isLogout; set { isLogout = value; } }
        #endregion
        #region 硬件属性
        /// <summary>
        /// 传送带配置
        /// </summary>
        private ConveyorModuleConfig config;
        /// <summary>
        /// 读码器
        /// </summary>
        private CodeReader codeReader;
        /// <summary>
        /// 传送轴
        /// </summary>
        private IAxis axisT;
        public IAxis AxisT { get => axisT; }
        /// <summary>
        /// 调宽轴
        /// </summary>
        private IAxis axisW;
        public IAxis AxisW { get => axisW; }
        /// <summary>
        /// 停止气缸
        /// </summary>
        private ICylinder stopCylinder;
        public ICylinder StopCylinder { get => stopCylinder; }
        /// <summary>
        /// 下压气缸
        /// </summary>
        private ICylinder pressCylinder;
        public ICylinder PressCylinder { get => pressCylinder; }
        /// <summary>
        /// 减速气缸
        /// </summary>
        //private ICylinder decelCylinder;
        //public ICylinder DececlCylinder { get => decelCylinder; }
        /// <summary>
        /// 进板感应器
        /// </summary>
        private ISensor InputSensor;
        /// <summary>
        /// 减速感应器
        /// </summary>
        private ISensor DecelSensor;
        /// <summary>
        /// 停板感应器
        /// </summary>
        private ISensor StopSensor;
        /// <summary>
        /// 出板感应器
        /// </summary>
        private ISensor OutputSensor;
        /// <summary>
        /// Smema功能
        /// </summary>
        public SmemaAction Smema { get; set; }
        #endregion
        #region 流程属性
        /// <summary>
        /// 读码器数据回调
        /// </summary>
        public Action<int, string> CodeReaderCallback;
        /// <summary>
        /// 检测结果回调
        /// </summary>
        public Action<string> CheckResultCallback { get; set; }
        /// <summary>
        /// 报警检测
        /// </summary>
        private AlarmDetect alarmDetect = new AlarmDetect();
        /// <summary>
        /// 主任务线程
        /// </summary>
        private Thread MainThread;
        /// <summary>
        /// 主任务循环
        /// </summary>
        private bool MainLoop = false;
        /// <summary>
        /// 主任务状态机
        /// </summary>
        private ModuleTaskStateE runTaskStep;
        /// <summary>
        /// 复位状态机
        /// </summary>
        private ResetStepE resetStep;
        /// <summary>
        /// 复位时间
        /// </summary>
        private DateTime resetTime;
        /// <summary>
        /// 是否复位调宽轴
        /// </summary>
        private bool isResetAxisW;
        /// <summary>
        /// 调宽轴基点
        /// </summary>
        private double basePoint;
        /// <summary>
        /// 是否有板
        /// </summary>
        private bool isHasBoard;
        /// <summary>
        /// 读码超时
        /// </summary>
        private Int32 readCodeTimeOut;
        /// <summary>
        /// 检测超时
        /// </summary>
        protected Int32 detectTimeOut;

        /// <summary>
        /// 进板超时
        /// </summary>
        protected Int32 InBoard;
        /// <summary>
        /// 检测状态
        /// </summary>
        private AutoStepE autoStep;
        /// <summary>
        /// 进板时间
        /// </summary>
        private DateTime inputTime;
        /// <summary>
        /// 条码校验结果
        /// </summary>
        private ConcurrentQueue<int> readCodeCheckQueue = new ConcurrentQueue<int>();
        /// <summary>
        /// 条码数据
        /// </summary>
        private string qrCodeData;
        /// <summary>
        /// 是否检测模式
        /// </summary>
        private bool IsDetect = false;
        /// <summary>
        /// 是否单次
        /// </summary>
        private bool IsSingle = false;

        /// <summary>
        /// 直通模式
        /// </summary>
        private bool isPassmode = false;


        public bool bOpenBeepbB = false;

        /// <summary>

        private ConcurrentDictionary<int, GrabInfo> cameras = new ConcurrentDictionary<int, GrabInfo>();
        #endregion
        #region 模组初始化
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="name"></param>
        public ConveyorModule(ConveyorModuleConfig moduleConfig)
        {
            config = moduleConfig;
            if (InitHardwareModule() != 0)
            {
                return;
            }
            InitAlarmModule();
            basePoint = config.AxisWPosition;
            runTaskStep = ModuleTaskStateE.Idle;
            isEnable = true;
            MainLoop = true;
            MainThread = new Thread(new ThreadStart(MainTaskFunction));
            MainThread.IsBackground = true;
            MainThread.Priority = ThreadPriority.Highest;
            MainThread.Start();
        }
        /// <summary>
        /// 初始化硬件模组
        /// </summary>
        private int InitHardwareModule()
        {
            codeReader = new CodeReader(config.ReaderConfi);
            codeReader.DataUpload = CodeReaderData;
            axisT = MotionDevice.Instance.GetAxis(config.AxisT);
            if (AxisT == null)
            {
                Logout($"T轴未配置.");
                return -1;
            }
            axisW = MotionDevice.Instance.GetAxis(config.AxisW);
            if (AxisW == null)
            {
                Logout($"W轴未配置.");
                return -1;
            }

            IDoBit stopDout = config.Direction == LineDirectionE.Left ? MotionDevice.Instance.DoBit(config.Cylinder3) 
                    : MotionDevice.Instance.DoBit(config.Cylinder1);
            IDoBit pressDout = MotionDevice.Instance.DoBit(config.Cylinder2);
            if (stopDout == null || pressDout == null)
            {
                Logout($"气缸未配置");
                return -1;
            }
            stopCylinder = new AirCylinder(new CylinderConfig() { Name = "阻挡气缸", Dout = stopDout });
            pressCylinder = new AirCylinder(new CylinderConfig() { Name = "压紧气缸", Dout = pressDout});
            //decelCylinder = new AirCylinder(new CylinderConfig() { Name = "阻挡气缸", Dout = });

            IDiBit inputDin = config.Direction == LineDirectionE.Left ? MotionDevice.Instance.DiBit(config.Sensor1) 
                : MotionDevice.Instance.DiBit(config.Sensor4);
            IDiBit decelDin = config.Direction == LineDirectionE.Left ? MotionDevice.Instance.DiBit(config.Sensor2)
                : MotionDevice.Instance.DiBit(config.Sensor3);
            IDiBit stopDin = config.Direction == LineDirectionE.Left ? MotionDevice.Instance.DiBit(config.Sensor3) 
                : MotionDevice.Instance.DiBit(config.Sensor2);
            IDiBit outputDin = config.Direction == LineDirectionE.Left ? MotionDevice.Instance.DiBit(config.Sensor4) 
                : MotionDevice.Instance.DiBit(config.Sensor1);
            if (inputDin == null || decelDin == null || stopDin == null || outputDin == null)
            {
                Logout($"感应器未配置");
                return -1;
            }

            InputSensor = new SensorFilter(new SensorConfig() { Name = "入口感应器", Din = inputDin});
            DecelSensor = new SensorFilter(new SensorConfig() { Name = "减速感应器", Din = decelDin });
            StopSensor = new SensorFilter(new SensorConfig() { Name = "停板感应器", Din = stopDin });
            OutputSensor = new SensorFilter(new SensorConfig() { Name = "出口感应器", Din = outputDin });

            Smema = new SmemaAction() 
            { 
                DiFrontReady = MotionDevice.Instance.DiBit(config.DiFrontReady),
                DiAfterReady = MotionDevice.Instance.DiBit(config.DiAfterReady),
                DoFrontReady = MotionDevice.Instance.DoBit(config.DoFrontReady),
                DoAfterReady = MotionDevice.Instance.DoBit(config.DoAfterReady),
                DoCheckReady = MotionDevice.Instance.DoBit(config.DoCheckReady)
            };
            if (Smema.DiFrontReady == null ||Smema.DiAfterReady == null || Smema.DoFrontReady == null
                || Smema.DoAfterReady == null || Smema.DoCheckReady == null)
            {
                Logout($"Smema未配置");
                return -1;
            }

            Logout("模组初始化完成.");

            return 0;
        }
        /// <summary>
        /// 释放模组
        /// </summary>
        public void Dispose()
        {
            MainLoop = false;
            codeReader.Close();
        }
        /// <summary>
        /// 日志输出
        /// </summary>
        /// <param name="loginfo"></param>
        private void Logout(string loginfo)
        {
            Logger.Logout($"{config.Name}：" + loginfo);
        }
        /// <summary>
        /// 读码器数据回调
        /// </summary>
        /// <param name="code"></param>
        private void CodeReaderData(string code)
        {
            CodeReaderCallback?.Invoke(config.ModuleKey, code);
        }
        #endregion
        #region 模组报警
        /// <summary>
        /// 初始化报警模组
        /// </summary>
        private void InitAlarmModule()
        {
            alarmDetect.LogoutCallback = Logout;
            InitAxisAlarm(axisW);
            InitCodeReaderTimeoutAlarm();
            InitConveyorTimeoutAlarm();
            InitResultTimeoutAlarm();
        }
        /// <summary>
        /// 初始化轴报警
        /// </summary>
        /// <param name="axis"></param>
        private void InitAxisAlarm(IAxis axis)
        {
            var alarm = new AlarmItem();
            alarm.ErrorID = config.ModuleKey + 0x100;
            alarm.Message = $"{axis.Config.Name}";
            alarm.Level = AlarmLevelE.Warning;
            alarm.IsAlarmCallback = new Func<bool>(() =>
            {
                bool isAlm = false;
                MotorStatus status = axis.GetStatus();
                alarm.Message = "";
                if (status != null)
                {
                    isAlm = status.ElNegLimit || status.ElNegLimit || status.EmgStop || status.ServoAlarm;
                    if (isAlm)
                    {
                        alarm.Message = $"{axis.Config.Name}" + (status.ElPosLimit ? "正限位" : "")
                        + (status.ElNegLimit ? "负限位" : "") + (status.ServoAlarm ? "伺服异常" : "");
                    }
                }

                return isAlm;
            });
            alarmDetect.AlarmItems.Add(alarm);
        }
        /// <summary>
        /// 初始化读码器超时报警
        /// </summary>
        private void InitCodeReaderTimeoutAlarm()
        {
            var alarm = new AlarmItem();
            alarm.ErrorID = 1;
            alarm.Message = $"{config.Name}返回结果ID异常|读码超时";
            alarm.Level = AlarmLevelE.Error;
            alarm.IsAlarmCallback = new Func<bool>(() =>
            {
                return readCodeTimeOut == 1;
            });
            alarmDetect.AlarmItems.Add(alarm);
        }
        /// <summary>
        /// 初始化传送超时报警
        /// </summary>
        private void InitConveyorTimeoutAlarm()
        {
            var alarm = new AlarmItem();
            alarm.ErrorID = 1;
            alarm.Message = $"{config.Name}传送超时";
            alarm.Level = AlarmLevelE.Error;
            alarm.IsAlarmCallback = new Func<bool>(() =>
            {
                return InBoard == 1;
            });
            alarmDetect.AlarmItems.Add(alarm);
        }

        /// <summary>
        /// 初始化检测结果超时报警
        /// </summary>
        private void InitResultTimeoutAlarm()
        {
            var alarm = new AlarmItem();
            alarm.ErrorID = 1;
            alarm.Message = $"{config.Name}获取检测结果超时";
            alarm.Level = AlarmLevelE.Warning;
            alarm.IsAlarmCallback = new Func<bool>(() =>
            {
                return detectTimeOut == 1;
            });
            alarmDetect.AlarmItems.Add(alarm);
        }

        /// <summary>
        /// 报警处理
        /// </summary>
        private void AlarmProcess()
        {
            alarmDetect.AlarmForeach();
            if ((runTaskStep != ModuleTaskStateE.Resetting && alarmDetect.IsError())
                || AlarmDevice.Instance.IsAlarm())
            {
                SetMainTaskState(ModuleTaskStateE.Error);
            }
        }
        #endregion
        #region 单段传送
        /// <summary>
        /// 传送带正向
        /// </summary>
        private void ConveyorForward()
        {
            if (config.Direction == LineDirectionE.Left)
            {
                axisT.MoveForward();
            }
            else
            {
                axisT.MoveBackward();
            }
        }
        /// <summary>
        /// 传送带反向
        /// </summary>
        private void ConveyorBackward()
        {
            if (config.Direction == LineDirectionE.Left)
            {
                axisT.MoveBackward();
            }
            else
            {
                axisT.MoveForward();
            }
        }
        /// <summary>
        /// 初始状态
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepInit()
        {
            Logout($"在线模式初始化.");
            InBoard = 0;
            detectTimeOut = 0;
            readCodeTimeOut = 0;
            inputTime = DateTime.Now;
            StopCylinder.MoveToBase();
            PressCylinder.MoveToBase();
            AxisT.MoveStop();
            Smema.FrontReadyTurnOff();
            Smema.AfterReadyTurnOff();



            if (isPassmode)
            {
                if (StopSensor.IsOn())  //板子中间,有板直接就出了
                {
                    ConveyorForward();
                    return AutoStepE.OutputPause;
                }
                Logout("等待进板.....");
                return AutoStepE.InputWait;
            }
            else if (IsDetect)
            {
                if (StopSensor.IsOn() || OutputSensor.IsOn())  //板子要回到上料位置
                {
                    Logout("轨道有板先回到上料位.....");
                    axisT.SetMualSpeed();
                    PressCylinder.MoveToBase();
                    StopCylinder.MoveToBase();
                    ConveyorBackward();
                    inputTime = DateTime.Now;

                    return AutoStepE.InPutBoard;
                }

            }

            if (IsDetect && !IsSingle)
            {

                Logout("等待进板.....");
                return AutoStepE.InputWait;
                //return AutoStepE.ReadCodeWait; //开启了扫码才会进扫码流程，暂时屏蔽

            }
            else
            {
                Logout("等待进板.....");
                return AutoStepE.InputWait;
            }


        }

        
        private AutoStepE StepReturnStart()
        {
            if (InputSensor.IsOn())  
            {
                return AutoStepE.Exit;  //手动板子回上料位,退出
            }
            else
            {
                Logout("回到上料位.....");
                axisT.SetMualSpeed();
                PressCylinder.MoveToBase();
                StopCylinder.MoveToBase();
                ConveyorBackward();
                inputTime = DateTime.Now;

                return AutoStepE.InPutBoard;
            }

        }


        /// <summary>
        /// 回到上料位置
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepInPutBoard()
        {
            for (int k = 0; k < 3; k++)
            {
                if (InputSensor.IsOn())
                {

                    AxisT.EmgStop();
                    ThreadHelper.Delay(1);
                    AxisT.EmgStop();
                    if (IsDetect)
                        axisT.SetAutoSpeed();

                    Logout($"进板口有板.");
                    isHasBoard = true;

                    axisT.SetAutoSpeed();

                    if (!IsDetect)   //手动板子回上料位,退出
                    {
                        return AutoStepE.Exit;
                    }

                    return AutoStepE.Init;
                }
                else
                    ThreadHelper.Delay(1);
            }



            if (TimeOutCheck())
            {
                Logout("异常：送板回上料位,超时异常...Wait");
                return AutoStepE.Wait;
            }

           

            return  AutoStepE.InPutBoard;
        }

        /// <summary>
        /// 扫码就绪
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepReadCodeWait()
        {
            if (AxisT.IsCheckDone())
            {
                if (Smema.IsFrontReady() || InputSensor.IsOn())
                {
                    codeReader.TriggerOn();
                    inputTime = DateTime.Now;
                    return AutoStepE.ReadCodeRecv;
                }
            }

            return AutoStepE.ReadCodeWait;
        }
        /// <summary>
        /// 扫码读取
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepReadCodeRecv()
        {
            codeReader.GetQRCodeID(ref qrCodeData);
            if (qrCodeData == string.Empty)
            {
                if (TimeOutCheck())
                {
                    return AutoStepE.ReadCodeWait;
                }

                return AutoStepE.ReadCodeRecv;
            }
            if (qrCodeData == "Disable")
            {
                Logout("扫码枪未启用.");
                qrCodeData = "";
                return AutoStepE.InputWait;
            }
            else
            {
                readCodeTimeOut = 0;
                CodeReaderData(qrCodeData);
                Logout("读取条码值: " + qrCodeData);
                return AutoStepE.ReadCodeCheck;
            }
        }
        /// <summary>
        /// 二维码校验
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepReadCodeCheck()
        {
            if (readCodeCheckQueue.TryDequeue(out var codeResult))
            {
                if (codeResult == 1)
                {
                    Logout("读码MES校验成功.");
                    readCodeTimeOut = 0;
                    return AutoStepE.InputWait;
                }
                else
                {
                    Logger.Logout("读码MES校验失败.");
                    readCodeTimeOut = 0;
                    return AutoStepE.ReadCodeWait;
                }
            }

            if (TimeOutCheck())
            {
                return AutoStepE.ReadCodeWait;
            }

            return AutoStepE.ReadCodeCheck;
        }

        /// <summary>
        /// 进板等待
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepInputWait()
        {
            if (AxisT.IsCheckDone())
            {

                if (OutputSensor.IsOn())
                {
                    return AutoStepE.OutputPause;
                }



                if (!InputSensor.IsOn())
                     Smema.FrontReadyTurnOn();

                if (Smema.IsFrontReady() || InputSensor.IsOn() /*|| DecelSensor.IsOn()*/)
                {
                    Logout($"在线模式上游有板,启动收板.{Smema.IsFrontReady()},{InputSensor.IsOn()}");
                    inputTime = DateTime.Now;
                    ConveyorForward();
                   
                    return AutoStepE.InputStart;
                }

            }

            return AutoStepE.InputWait;
        }
        /// <summary>
        /// 进料开始
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepInputStart()
        {
            if (!InputSensor.IsOn() /*&& !DecelSensor.IsOn()*/)
            {
                if (TimeOutCheck())
                {
                    Logout("异常：进板到上料感应器超时异常...Wait");
                    return AutoStepE.Wait;
                }
                return AutoStepE.InputStart;
            }
            else
            {
                Logout($"在线模式进板口收到上游来板");
                inputTime = DateTime.Now;
                Smema.FrontReadyTurnOff();
                if (!isPassmode)
                    StopCylinder.MoveToWork();
                else
                {
                    Logout($"直通等待板子到下料位");
                    return AutoStepE.OutputPause;
                }



                return AutoStepE.InputDecel;
            }
        }
        /// <summary>
        /// 进料减速
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepInputDecel()
        {
            if (!StopSensor.IsOn())
            {
                if (TimeOutCheck())
                {
                    Logout("异常：进板到停板感应器超时异常...Wait");
                    return AutoStepE.Wait;
                }
                return AutoStepE.InputDecel;
            }
            else
            {
                AxisT.EmgStop();   //先停止
                AxisT.SetAutoSpeed2();  //减速
                ConveyorForward();   //启动

                Logout($"在线模式取像口收到上游来板.");

                inputTime = DateTime.Now;
                
                return AutoStepE.InputStop;
            }
        }
        /// <summary>
        /// 进料停止
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepInputStop()
        {
            if (AxisT.IsCheckDone())
            {
                TimeSpan spn = DateTime.Now - inputTime;
                if ( spn.TotalMilliseconds >= 100)
                {
                    StopCylinder.MoveToBase();
                    inputTime = DateTime.Now;
                    Logout($"在线模式收回阻挡.");
                    WaiteGrabTime = DateTime.Now;
                    return AutoStepE.WaiteGrabCommand;
                }

                return AutoStepE.InputStop;
            }
            else
            {
                TimeSpan spn = DateTime.Now - inputTime;
                if (spn.TotalMilliseconds >= 600)
                {
                    AxisT.EmgStop();
                    inputTime = DateTime.Now;
                }
            }

            return AutoStepE.InputStop;
        }

        #region 取像必须要收到取像命令，不能自动取像

        private bool RecvdGrabCmd { get; set; } = false;
        private DateTime WaiteGrabTime {  get; set; }
        /// <summary>
        /// 等待取像命令
        /// </summary>
        private AutoStepE StepWaiteGrabCommand()
        {
            if (!IsDetect)
            {
                return AutoStepE.GrabStart;
            }
            if (RecvdGrabCmd && autoStep == AutoStepE.WaiteGrabCommand)
            {
                RecvdGrabCmd = false;
                return AutoStepE.GrabStart;
            }
            return AutoStepE.WaiteGrabCommand;
        }
        #endregion
        /// <summary>
        /// 取像开始
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepGrabStart()
        {
            TimeSpan spn = DateTime.Now - inputTime;
            if (spn.TotalMilliseconds >= 300)
            {
                inputTime = DateTime.Now;
                PressCylinder.MoveToWork();
                Logout($"在线模式压紧上游来板.");
                if (IsDetect)
                {
                    DataCenter.Instance.ConveyorProductDataClear(config.ModuleKey);
                    cameras.ToList().ForEach(it =>
                    {
                        Logout($"通知{Enum.GetName(typeof(CameraModuleE), it.Key)}模组开始取像");
                        DataCenter.Instance.CameraEnqueue(it.Key, new ProductData()
                        {
                            QrCode = qrCodeData,
                            Station = config.ModuleKey,
                        });
                        it.Value.IsGrabEnd = false;
                    });

                    return AutoStepE.GrabStop;
                }
                else
                {
                    Logout($"在线模式标定进板退出.");
                    return AutoStepE.Wait;
                }
            }
            
            return AutoStepE.GrabStart;            
        }

        /// <summary>
        /// 结束取像状态
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepGrabStop()
        {
            if (DataCenter.Instance.ConveyorTryDequeue(config.ModuleKey, out ProductData data))
            {
                if (data.QrCode == qrCodeData)
                {
                    if (cameras.ContainsKey(data.Station))
                    {
                        cameras[data.Station].IsGrabEnd = true;
                        cameras[data.Station].GrabUuid = data.Uuid;
                        Logout($"收到{Enum.GetName(typeof(CameraModuleE), data.Station)}模组完成取像");
                    }
                }
            }

            if (cameras.ToList().Exists(it => it.Value.IsGrabEnd == false))
            {
                return AutoStepE.GrabStop;
            }
            else
            {
                Logout($"在线模式收到拍照结束.");
                return AutoStepE.OutputStart;
            }
        }
        /// <summary>
        /// 出板开始
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepOutputStart()
        {
            PressCylinder.MoveToBase();
            inputTime = DateTime.Now;
            Logout($"在线模式收回压紧气缸.");
            return AutoStepE.OutputRunning;
        }

        /// <summary>
        /// 出板进行
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepOutputRunning()
        {
            TimeSpan span = DateTime.Now - inputTime;
            if (span.TotalMilliseconds >= 100)
            {
                Logout($"在线模式启动出板，传输至停板口等待");
                //先不给下游送板信号
                //Smema.AfterReadyTurnOn();

             
                inputTime = DateTime.Now;

                axisT.SetMualSpeed();
               // axisT.SetAutoSpeed();
                ConveyorForward();
               
                return AutoStepE.OutputPause;
            }

            return AutoStepE.OutputRunning; 
        }
        /// <summary>
        /// 出板暂停
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepOutputPause()
        {
            //T3 传输至 T4时，是否超时



            bool OK = true;
            for (int k = 0; k < 3; k++)
            {
                if (OutputSensor.IsOn())
                {
                    OK = true;

                    break;
                }
                else
                {
                    OK = false;

                }

            }
            if (!OK)
            {

                if (TimeOutCheck())
                {
                    Logout("异常：送板到下料位感应器超时异常...Wait");
                    return AutoStepE.Wait;
                }
                return AutoStepE.OutputPause;
            }


            //重新计时
            AxisT.EmgStop(); ThreadHelper.Delay(1); AxisT.EmgStop();

            if (IsDetect)
                axisT.SetAutoSpeed();


            if (!isPassmode)
            { 

                if (IsDetect && IsSingle) //循环测试,退出软件。等待下次调用再回来
                {
                    return AutoStepE.Exit;
                }

                if (!IsDetect) //手动出板退出软件
                {
                    return AutoStepE.Exit;
                }
             }


            Logout($".....下料位感应器检测完成,轨道暂停,等待检测或者复判结果" + DateTime.Now);
            inputTime = DateTime.Now;
            return AutoStepE.OutputWait;
            
        }
        /// <summary>
        /// 检测结果处理
        /// </summary>
        /// <returns>0-检测结果输出 -1-检测结果未出</returns>
        private int CheckResultProcess()
        {
            if (config.SmemaMode != 0)
            {
                //Logout($"NG ininin");
                if (cameras.ToList().Exists(itm => itm.Value.CheckUuid == ""))
                {
                   // Logout($"NG  return -11111111111 Value.CheckUuid == 空   ");
                    return -1;
                }


                if (cameras.ToList().Exists(itm => itm.Value.CheckUuid == null))
                {
                   // Logout($"NG  return -empty Value.CheckUuid == 空");
                    return -1;
                }
                if(cameras.Count <1 )
                {
                    Logout($"检测结果输出 NG  return -3 cameras.Count<1");
                    return -3;
                }

                if (!cameras.ToList().Exists(itm => itm.Value.CheckUuid != itm.Value.GrabUuid))
                {
                    if (cameras.Count < 1)
                    {
                        Logout($"检测结果输出 NG  return -3 cameras.Count<1_2");
                        return -3;
                    }
                    Logout($"查询是否有NG复判结果，{cameras?.ToList().FirstOrDefault().Value.GrabUuid}，checkId：{cameras?.ToList().FirstOrDefault().Value.CheckUuid}");
                    if (!cameras.ToList().Exists(itm => itm.Value.IsNg == false))
                    {
                        Logout($"在线检测模式复检NG.");

                        if (config.SmemaMode == 1)
                        {
                            Smema.AfterReadyTurnOn();
                            Smema.CheckReadyTurnOn();
                        }
                        else
                        {
                            Smema.AfterReadyTurnOff();
                            Smema.CheckReadyTurnOn();
                        }
                    }
                    else
                    {
                        Logout($"在线检测模式复检OK.");
                       
                         Smema.AfterReadyTurnOn();
                         Smema.CheckReadyTurnOff();
                        
                    }
                    cameras.ToList().ForEach(itm => itm.Value.CheckUuid = "");
                }
                else
                {
                    var info = cameras.ToList().Find(itm => itm.Value.CheckUuid != itm.Value.GrabUuid);
                
                    if (info.Value == null)
                    {
                        Logout($"NG  return -33333333333333");
                        return -3;
                    }
                    Logout($"在线检测模式复检失败,复检ID:{info.Value.CheckUuid},设备内ID:{info.Value.GrabUuid}.。请复判最新的板子");
                    CheckResultCallback?.Invoke(info.Value.CheckUuid);
                    return -2;
                }
            }
            else
            {
                Logout($"NG信号模式：smemaMode{config.SmemaMode}");
                Smema.AfterReadyTurnOn();
            }
            return 0;
        }
        /// <summary>
        /// 出板等待
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepOutputWait()
        {
            if (config.SmemaMode != 0)
            {
                if (!OutputSensor.IsOn())//
                {
                    ThreadHelper.Delay(150);
                    if (!OutputSensor.IsOn())                 
                    {
                        Logout($"在线模式出板口未检测到板.未复判被人为拿走,重新进板！");
                        inputTime = DateTime.Now;
                       
                        return AutoStepE.OutputFinish;
                    }
                }

               
            }


            if (IsDetect && !isPassmode)
            {
                if (TimeDetectOutCheck())
                {
                    Logout("异常：等待检测结果超时,请复判。。。"); 
                    inputTime = DateTime.Now;
                    return AutoStepE.OutputWait;
                }
            }

            if (AxisT.IsCheckDone())
            {

                if (isPassmode)
                {
                    Logout($"直通模式.等待出板信号或下料位拿板");
                    return AutoStepE.OutputWait2;
                }

                int nR = CheckResultProcess();
                if (nR != 0)
                {
                    if (nR == -3)
                    {
                       ThreadHelper.Delay(2000); //  不报警只提示，只是超时报警
               
                        return AutoStepE.OutputWait;
                        //Logout($"CheckResult异常-运行退出,请复位");
                        // readCodeTimeOut = 1;
                        // return AutoStepE.Exit;
                    }
                    if (nR == -2)
                    { 
                        ThreadHelper.Delay(2000);  //  不报警只提示，只是超时报警
                        return AutoStepE.OutputWait;
                       // Logout($"CheckResult复检ID异常-运行退出,请复位");
                        // readCodeTimeOut = 1;
                        // return AutoStepE.Exit;
                    }
                    if (!IsDetect)
                    {
                        Logout($"Wait return.");
                        return AutoStepE.Wait;
                    }
                    
         
                    return AutoStepE.OutputWait;
                }
                else
                {
                    Logout($"关闭蜂鸣器3.");
                    return AutoStepE.OutputWait2;
                }
            }
            else
                return AutoStepE.OutputWait;


            //if (Smema.IsAfterReady())
            //{
            //    // SetCheckResultVaule();
            //    Logout($"在线模式下游就绪,启动出板.");
            //    ConveyorForward();
            //    inputTime = DateTime.Now;
            //    // Smema.AfterReadyTurnOn();

            //    return AutoStepE.OutputFinish;
            //}
            //else
            //{
            //    if (IsDetect && !IsSingle)
            //    {
            //        return AutoStepE.OutputWait;
            //    }
            //    else
            //    {
            //        return AutoStepE.Exit;
            //    }
            //}
        }

        private AutoStepE StepOutputWait2()
        {
            if (bOpenBeepbB)
                bOpenBeepbB = false;
            if (!OutputSensor.IsOn())
            {
                ThreadHelper.Delay(100);
                if (!OutputSensor.IsOn())
                {
                    ThreadHelper.Delay(500);

                    Logout($"出板口板子被人为拿走了。。。.");
                    inputTime = DateTime.Now;
                    return AutoStepE.OutputFinish;
                }
                else
                    return AutoStepE.OutputWait2;
            }
            if (Smema.IsAfterReady())  
            {
                // SetCheckResultVaule();
                Logout($"在线模式下游就绪,启动出板.");
                ConveyorForward();
                inputTime = DateTime.Now;
                // Smema.AfterReadyTurnOn();

                return AutoStepE.OutputFinish;
            }
            else
            {
                if ( (IsDetect && !IsSingle) || isPassmode) //非循环测试继续等信号
                {
                    ThreadHelper.Delay(1);
                    return AutoStepE.OutputWait2;
                }
                else
                {
                    return AutoStepE.Exit;
                }
            }
        }

        /// <summary>
        /// 出板完成
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepOutputFinish()
        {
            if (bOpenBeepbB)
                bOpenBeepbB = false;
            if (OutputSensor.IsOn())
            {
               
                if (TimeOutCheck())
                {
                    Logout("异常：送板出去超时异常超时异常...Wait");
                    return AutoStepE.Wait;
                }
                return AutoStepE.OutputFinish;
            }
            else
            {

                Smema.AfterReadyTurnOff();
                Smema.CheckReadyTurnOff();

                Logout($"在线模式出板口无板,本次检测结束.");

                if ((IsDetect && !IsSingle) || isPassmode)
                {
                    if (isPassmode)
                    {
                        ThreadHelper.Delay(1000);
                    }
                
                    return AutoStepE.Init;
                }
                else
                {
                    return AutoStepE.Exit;
                }
            }
        }
        /// <summary>
        /// 退出状态
        /// </summary>
        /// <returns></returns>
        private AutoStepE StepExit()
        {
            if (bOpenBeepbB)
                bOpenBeepbB = false;
            Logout($"在线模式退出.");
            Smema.FrontReadyTurnOff();
            Smema.AfterReadyTurnOff();
            Smema.CheckReadyTurnOff();
            StopCylinder.MoveToBase();
            PressCylinder.MoveToBase();
            AxisT.EmgStop();
            ThreadHelper.Delay(1);
            AxisT.EmgStop();
            if (IsDetect)
                axisT.SetAutoSpeed();


            cameras.Clear();
            IsDetect = false;
            IsSingle = false;
            DataCenter.Instance.ConveyorProductDataClear(config.ModuleKey);
            return AutoStepE.Wait;
        }
        /// <summary>
        /// 等待状态步完成
        /// </summary>
        public ModuleTaskStateE TaskStepAuto()
        {
            switch (autoStep)
            {
                case AutoStepE.Init:
                    autoStep = StepInit();
                    break;
                case AutoStepE.ReadCodeWait:
                    autoStep = StepReadCodeWait();
                    break;
                case AutoStepE.ReadCodeRecv:
                    autoStep = StepReadCodeRecv();
                    break;
                case AutoStepE.ReadCodeCheck:
                    autoStep = StepReadCodeCheck();
                    break;
                case AutoStepE.InputWait:
                    autoStep = StepInputWait();
                    break;
                case AutoStepE.InputStart:
                    autoStep = StepInputStart();
                    break;
                case AutoStepE.InputDecel:
                    autoStep = StepInputDecel();
                    break;
                case AutoStepE.InputStop:
                    autoStep = StepInputStop();
                    break;
                case AutoStepE.WaiteGrabCommand:
                    autoStep = StepWaiteGrabCommand();
                    break;
                case AutoStepE.GrabStart:
                    autoStep = StepGrabStart();
                    break;
                case AutoStepE.GrabStop:
                    autoStep = StepGrabStop();
                    break;
                case AutoStepE.OutputStart:
                    autoStep = StepOutputStart();
                    break;
                case AutoStepE.OutputRunning:
                    autoStep = StepOutputRunning();
                    break;
                case AutoStepE.OutputPause:
                    autoStep = StepOutputPause();
                    break;
                case AutoStepE.OutputWait:
                    autoStep = StepOutputWait();
                    break;
                case AutoStepE.OutputWait2:
                    autoStep = StepOutputWait2();
                    break;
                case AutoStepE.OutputFinish:
                    autoStep = StepOutputFinish();
                    break;
                case AutoStepE.Exit:
                    autoStep = StepExit();
                    break;
                case AutoStepE.InPutBoard:
                    autoStep = StepInPutBoard();
                    break;

                case AutoStepE.ReturnStart:
                    autoStep = StepReturnStart();
                    break;

                default:
                    break;
            }

            if (cameras.Count == 0)
            {
                autoStep = StepExit();
            }

            if (autoStep == AutoStepE.Wait)
            {
                Logout("++++++++++cameras.Clear()+++++++++++++++");
                cameras.Clear();
                return ModuleTaskStateE.Idle;
            }
            else
            {
                return ModuleTaskStateE.Running;
            }
        }
        /// <summary>
        /// 超时检测
        /// </summary>
        private bool TimeOutCheck()
        {
            TimeSpan span = DateTime.Now - inputTime;
            if (span.TotalSeconds >= config.Timeout)
            {
                if (autoStep == AutoStepE.ReadCodeRecv)
                {
                    readCodeTimeOut = 1;
                    Logout("在线模式读码超时.");
                    return true;
                }

                if (autoStep == AutoStepE.ReadCodeCheck)
                {
                    readCodeTimeOut = 1;
                    Logout("在线模式读码MES校验超时.");
                    return true;
                }
                InBoard = 1;
                Logout($"在线模式传送超时.");
            
                inputTime = DateTime.Now;
                StepExit();
                return true;
            }
            return false;
        }

        private bool TimeDetectOutCheck()
        {
            TimeSpan span = DateTime.Now - inputTime;
            if (span.TotalSeconds >= 30)
            {
                Logout($"等待检测结果超时.");

                Logout($"开启蜂鸣器.");
                if (!bOpenBeepbB)
                    bOpenBeepbB = true;   //


                //if (IsDetect)
                //{
                //    detectTimeOut = 1;
                //}
                inputTime = DateTime.Now;
                return true;
            }
            return false;
        }

        #endregion
        #region 模组复位
        /// <summary
        /// 复位初始化
        /// </summary>
        /// <returns></returns>
        private ResetStepE ResetStepInit()
        {
            Logout($"复位初始化.");
            resetTime = DateTime.Now;
            isHasBoard = false;
            detectTimeOut = 0;
            InBoard = 0;
            readCodeTimeOut = 0;
            Smema.FrontReadyTurnOff();
            Smema.AfterReadyTurnOff();
            Smema.CheckReadyTurnOff();
            PressCylinder.MoveToBase();
            StopCylinder.MoveToBase();
            if(bOpenBeepbB)
              bOpenBeepbB = false;
            if (InputSensor.IsOn())
            {
                Logout($"进板口有板.");
                isHasBoard = true;
                return ResetStepE.Finish;
            }

            if (OutputSensor.IsOn())
            {
                Logout($"出板口有板.");
                isHasBoard = true;
            }

            if (StopSensor.IsOn())
            {
                isHasBoard = true;
            }

            axisT.SetMualSpeed();
            ConveyorBackward();

            return ResetStepE.BeltBackward;
        }
        /// <summary>
        /// 复位传送皮带
        /// </summary>
        /// <returns></returns>
        private ResetStepE ResetStepBeltBackward()
        {
        
            for (int k = 0; k < 3; k++)
            {
                if (InputSensor.IsOn())
                {
                 
                    AxisT.EmgStop();
                    ThreadHelper.Delay(1);
                    AxisT.EmgStop();
                    if (IsDetect)
                        axisT.SetAutoSpeed();

                    Logout($"进板口有板.");
                    isHasBoard = true;
                    return ResetStepE.Finish;
                }
                else
                    ThreadHelper.Delay(1);
            }

             
           
            if (!ResetTimeCheck())
            {
                return ResetStepE.BeltBackward;
            }

            axisT.SetAutoSpeed();

            if (!isHasBoard && isResetAxisW)
            {
                return ResetStepE.WidthMoveHome;
            }
            else
            {
                return ResetStepE.Finish;
            }
            
        }
        /// <summary>
        /// 调宽轴运动回零
        /// </summary>
        /// <returns></returns>
        private ResetStepE ResetStepWidthMoveHome()
        {
            if (AxisW.IsCheckDone())
            {
                Logout("调宽轴启动回零.");
                resetTime = DateTime.Now;
               // AxisW.MoveHome();
                return ResetStepE.WidthWaitHome;
            }

            return ResetStepE.WidthMoveHome;
        }
        /// <summary>
        /// 调宽轴等待回零
        /// </summary>
        /// <returns></returns>
        private ResetStepE ResetStepWidthWaitHome()
        {
            if (AxisW.IsCheckDone() && AxisW.IsHomeFinish())
            {
                Logout($"调宽轴回零成功.");
                return ResetStepE.WidthMoveBase;
            }
            else
            {
                return ResetStepE.WidthWaitHome;
            }
        }
        /// <summary>
        /// 等待运动到原点
        /// </summary>
        /// <returns></returns>
        private ResetStepE ResetStepWidthMoveBase()
        {
            AxisW.SetAutoSpeed();
           // AxisW.MoveAbs((float)basePoint);
            Logout($"调宽轴运动到基点:{Math.Round(basePoint, 2)}");
            return ResetStepE.WidthWaitBase;
        }
        /// <summary>
        /// 等待运动到基点
        /// </summary>
        /// <returns></returns>
        private ResetStepE ResetStepWidthWaitBase()
        {
            if (AxisW.IsCheckDone())
            {
                Logout("调宽轴结束.");
                return ResetStepE.Finish;
            }
            else
            {
                return ResetStepE.WidthWaitBase;
            }
        }
        /// <summary>
        /// 复位流程
        /// </summary>
        public ModuleTaskStateE ResetFunction()
        {
            switch (resetStep)
            {
                case ResetStepE.Init:
                    resetStep = ResetStepInit();
                    break;
                case ResetStepE.BeltBackward:
                    resetStep = ResetStepBeltBackward();
                    break;
                case ResetStepE.WidthMoveHome:
                    resetStep = ResetStepWidthMoveHome();
                    break;
                case ResetStepE.WidthWaitHome:
                    resetStep = ResetStepWidthWaitHome();
                    break;
                case ResetStepE.WidthMoveBase:
                    resetStep = ResetStepWidthMoveBase();
                    break;
                case ResetStepE.WidthWaitBase: 
                    resetStep = ResetStepWidthWaitBase();
                    break;
                case ResetStepE.Finish:
                    break;
                default:
                    break;
            }

            if (resetStep == ResetStepE.Finish)
            {
                if (IsDetect || isPassmode)
                {
                    return ModuleTaskStateE.Running;
                }
                else
                {
                    return ModuleTaskStateE.Idle;
                }
            }
            else
            {
                return ModuleTaskStateE.Resetting;
            }
        }
        /// <summary>
        /// 复位超时检测
        /// </summary>
        private bool ResetTimeCheck()
        {
            DateTime dateTime = DateTime.Now;
            TimeSpan span = dateTime - resetTime;
            if ((int)span.TotalSeconds >= 5)
            {
                resetTime = dateTime;
                resetStep = ResetStepE.Finish;
                AxisT.EmgStop();
                if(IsDetect)
                    axisT.SetAutoSpeed();
                if (!isHasBoard)
                {
                    isHasBoard = false;
                    Logout($"未检测到有板.");
                }
                return true;
            }

            return false;
        }
        /// <summary>
        /// 复位开始
        /// </summary>
        public int ResetStart(bool isResetWidth)
        {
            if (runTaskStep == ModuleTaskStateE.Resetting)
            {
                Logout($"正在复位中");
                return 0;
            }

            if (runTaskStep != ModuleTaskStateE.Idle 
                && runTaskStep != ModuleTaskStateE.Error)
            {
                Logout($"复位失败，当前状态:{runTaskStep}");
                return -1;
            }
            else
            {
                Logout($"收到复位操作");
                isResetAxisW = isResetWidth;
                resetTime = DateTime.Now;
                resetStep = (Int32)ResetStepE.Init;
                SetMainTaskState(ModuleTaskStateE.Resetting);
                return 0;
            }
        }
        #endregion
        #region 模组任务
        /// <summary>
        /// 设置主任务状态
        /// </summary>
        /// <param name="state"></param>
        private void SetMainTaskState(ModuleTaskStateE state)
        {
            if (runTaskStep == ModuleTaskStateE.Running 
                && state == ModuleTaskStateE.Error)
            {
                StepExit();
            }

            if (runTaskStep != state)
            {
                Logout($"{runTaskStep}==>{state}");
                runTaskStep = state;
            }
        }
        /// <summary>
        /// 读取感应器状态
        /// </summary>
        private void ReadSensorState()
        {
            InputSensor.ReadStatus();
            DecelSensor.ReadStatus();
            StopSensor.ReadStatus();
            OutputSensor.ReadStatus();
        }
        /// <summary>
        /// 任务状态处理
        /// </summary>
        private void TaskStateProcess()
        {
            switch (runTaskStep)
            {
                case ModuleTaskStateE.Idle:
                    #region 空闲状态 手动控制
                    if (autoStep == AutoStepE.WaiteGrabCommand && -1 != GrabCameraKey)
                    {
                        Logout($"通知{Enum.GetName(typeof(CameraModuleE), GrabCameraKey)}模组开始取像");
                        DataCenter.Instance.CameraEnqueue(GrabCameraKey, new ProductData() { QrCode = "", Station = config.ModuleKey });
                        autoStep = AutoStepE.Wait;
                        GrabCameraKey = -1;
                    }
                    #endregion
                    break;
                case ModuleTaskStateE.Running:
                    #region 执行运动 执行自动流程
                    SetMainTaskState(TaskStepAuto());
                    #endregion
                    break;
                case ModuleTaskStateE.Error:
                    break;
                case ModuleTaskStateE.Resetting:
                    #region 执行复位流程
                    var resetSt = DataCenter.Instance.GetCameraResetStatus();
                    if (resetSt == DataCenter.ResetStatusE.Finish)
                    {
                        SetMainTaskState(ResetFunction());
                    }
                    else if (resetSt == DataCenter.ResetStatusE.Failed)
                    {
                        SetMainTaskState(ModuleTaskStateE.Idle);
                    }
                    #endregion
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 主线程
        /// </summary>
        private void MainTaskFunction()
        {
            while (MainLoop)
            {
                try
                {
                    AlarmProcess();
                    ReadSensorState();
                    TaskStateProcess();
                    ThreadHelper.Delay(1);
                }
                catch (Exception ex)
                {
                    Logger.Logerr($"{ex}");
                }
            }
        }
        #endregion
        private int GrabCameraKey = -1; //采集命令的key
        #region 外部接口
        /// <summary>
        /// 启动自动
        /// </summary>
        /// <param name="mode">0-自动 1-进板 2-出板</param>
        /// <returns></returns>
        public int AutoStart(ConveyorWorkModeE mode, int cameraKey = -1)
        {
            if (IsDetect)
            {
                if (!cameras.ContainsKey(cameraKey))
                {
                    if (!cameras.TryAdd(cameraKey, new GrabInfo() { IsGrabEnd = false }))
                    {
                        Logout($"检测启动失败,添加相机模组失败.");
                        return -1;
                    }
                }
                Logout($"在检测状态中");
                return 0;
            }

            if (runTaskStep != ModuleTaskStateE.Idle)
            {
                Logout($"检测启动失败，当前状态:{runTaskStep}");
                return -1;
            }

            if (!cameras.ContainsKey(cameraKey) && mode != ConveyorWorkModeE.GrabImage)
            {
                if (!cameras.TryAdd(cameraKey, new GrabInfo() { IsGrabEnd = false }))
                {
                    Logout($"检测启动失败,添加相机模组失败.");
                    return -1;
                }
            }

            switch (mode)
            {
                case ConveyorWorkModeE.Input:
                    if (OutputSensor.IsOn() /*|| DecelSensor.IsOn()*/ || StopSensor.IsOn())
                    {
                        Logout($"进板启动失败,轨道有板.");
                        return -1;
                    }
                    else if (!InputSensor.IsOn())
                    {
                        Logout($"进板启动失败,上料位无板.");
                        return -1;
                    }
                    else
                    {
                        IsDetect = false;
                        isPassmode = false;
                        AxisT.SetMualSpeed();
                        autoStep = AutoStepE.Init;
                        SetMainTaskState(ModuleTaskStateE.Running);
                    }
                    break;
                case ConveyorWorkModeE.Output:
                    if (OutputSensor.IsOn())
                    {
                        Logout($"出板失败,下料位有板.");
                        return -1;
                    }
                    if (!InputSensor.IsOn()  && !StopSensor.IsOn())
                    {
                        Logout($"出板失败,设备内和上料位无板.");
                        return -1;
                    }
                    isPassmode = false;
                    IsDetect = false;
                    AxisT.SetMualSpeed();               
                    autoStep = AutoStepE.OutputStart;
                    SetMainTaskState(ModuleTaskStateE.Running);
                    break;
                case ConveyorWorkModeE.ReturnPut:
                    if (InputSensor.IsOn())
                    {
                        Logout($"回上料位失败,上料位有板.");
                        return -1;
                    }
                    if (!OutputSensor.IsOn() && !StopSensor.IsOn())
                    {
                        Logout($"回上料位失败,设备内和下料位无板.");
                        return -1;
                    }
                    isPassmode = false;
                    IsDetect = false;
                    AxisT.SetMualSpeed();
                    autoStep = AutoStepE.ReturnStart;
                    SetMainTaskState(ModuleTaskStateE.Running);
                    break;
                case ConveyorWorkModeE.Detect:                 //直接正常生产
                    Logout($"启动Detect.");
                    IsDetect = true;
                    IsSingle = false;
                    isPassmode = false;
                    AxisT.SetAutoSpeed();
                    autoStep = AutoStepE.Init;
                    ResetStart(false);
                    SetMainTaskState(ModuleTaskStateE.Resetting);    //Resetting  启动检测复位.不回零调宽
                    break;
                case ConveyorWorkModeE.GrabImage:
                    //Logout($"通知{Enum.GetName(typeof(CameraModuleE), cameraKey)}模组开始取像");
                    //DataCenter.Instance.CameraEnqueue(cameraKey, new ProductData() { QrCode = "", Station = config.ModuleKey });
                    GrabCameraKey = cameraKey;
                    autoStep = AutoStepE.WaiteGrabCommand;
                    break;
                case ConveyorWorkModeE.SingleDetect: //循环单次检测,用于空跑
                    Logout($"启动SingleDetect.");
                    isPassmode = false;
                    IsDetect = true;
                    IsSingle = true;
                    AxisT.SetAutoSpeed();
                    autoStep = AutoStepE.Init;
                    ResetStart(false);
                    SetMainTaskState(ModuleTaskStateE.Resetting);      //Resetting  启动检测复位.不回零调宽
                    break;
                case ConveyorWorkModeE.PassModeRun:
                    Logout($"开启直通PassModeRun");
                    IsDetect = false;
                    IsSingle = false;
                    isPassmode = true;
                    AxisT.SetAutoSpeed();
                    autoStep = AutoStepE.Init;
                    ResetStart(false);  //这个会影响状态？
                    SetMainTaskState(ModuleTaskStateE.Resetting);      // Resetting 启动直通复位.不回零调宽
                    break;

                default:
                    break;
            }

            return 0;
        }
        /// <summary>
        /// 自动停止
        /// </summary>
        /// <returns></returns>
        public int AutoStop(int cameraKey)
        {
            if (cameras.ContainsKey(cameraKey))
            {
                if (!cameras.TryRemove(cameraKey, out var info))
                {
                    Logout($"检测停止失败");
                }
            }

            return 0;
        }
        /// <summary>
        /// 模块状态
        /// </summary>
        /// <returns></returns>
        public ModuleTaskStateE ModuleTaskState()
        {
            return runTaskStep;
        }
        /// <summary>
        /// 是否有板
        /// </summary>
        /// <returns></returns>
        public bool IsHasBoard()
        {
            return InputSensor.IsOn() || DecelSensor.IsOn() || StopSensor.IsOn() || OutputSensor.IsOn();
        }
        /// <summary>
        /// 保存调宽轴位置
        /// </summary>
        public void SaveAxisWPosition()
        {
            Task.Run(() =>
            {
                while (!AxisW.IsCheckDone())
                {
                    ThreadHelper.Delay(1);
                }
                double dPosit = 0;
                AxisW.GetPositionUnit(ref dPosit);



                dPosit += basePoint;
                config.AxisWPosition = (float)dPosit;



                HardwareConfi.Instance.SetWAxisPosition((ConveyorModuleE)config.ModuleKey, (float)config.AxisWPosition);
            });
        }
        /// <summary>
        /// 设置轨道宽度
        /// </summary>
        /// <param name="width"></param>
        public int SetTrackWidth(float width)
        {
            if (IsHasBoard())
            {
                Logout($"传送带有板");
                return -1;
            }

            if (!axisW.IsCheckDone())
            {
                Logout($"运动未停止");
                return -1;
            }

            double pos = axisW.Config.MoveDir == 0 ? width - config.AxisWCheck - config.AxisWPosition : config.AxisWCheck - width + config.AxisWPosition;
            axisW.SetMualSpeed();

            //double dPosit = 0;
            //AxisW.GetPositionUnit(ref dPosit);
            //pos = pos - dPosit;
            if (0!= axisW.MoveRel(pos))
            {
                Logout($"软件限位");
                return -1;
            }
            SaveAxisWPosition();
            return 0;
        }
        /// <summary>
        /// 获取轨道宽度
        /// </summary>
        /// <param name="width"></param>
        public void GetTrackWidth(ref float width)
        {
            //double pos = 0.0f;
            //AxisW.GetPositionUnit(ref pos);
            double pos = 0;
            //Logout($"GetTrackWidth-GetPositionUnit：{pos}.");
            //Logout($"GetTrackWidth-AxisWCheck：{config.AxisWCheck}.");
            width = (float)(AxisW.Config.MoveDir == 0 ? pos + config.AxisWCheck + config.AxisWPosition : config.AxisWCheck - pos - config.AxisWPosition);
        }
        /// <summary>
        /// 条码校验结果
        /// </summary>
        /// <param name="result">0-失败 1-成功</param>
        public void SetQrCodeCheckResult(int result)
        {
            while (readCodeCheckQueue.TryDequeue(out var sts)) ;
            readCodeCheckQueue.Enqueue(result);
        }
        /// <summary>
        /// 设置检测结果模式
        /// </summary>
        /// <param name="isEnable"></param>
        public void SetCheckResultMode(int mode)
        {
            Logout($"设置NG信号是否生效：{mode}.");
            config.SmemaMode = mode;
        }
        /// <summary>
        /// 设置检测结果值
        /// </summary>
        /// <param name="pid"></param>
        /// <param name="isNG"></param>
        /// <returns></returns>
        public int SetCheckResultVaule(int moduleKey, string pid, bool isNG)
        {
            if (cameras.Count < 1)
            {
                Logout($"cameras不包含{moduleKey}.");
                return -1;
            }
            if (!cameras.ContainsKey(moduleKey))
            {

                Logout($"cameras不包含{moduleKey}.");
                if (!cameras.TryAdd(moduleKey, new GrabInfo() { IsGrabEnd = false }))
                {
                    Logout($"检测启动失败,添加相机模组失败.");
                    return -1;
                }
            }
            cameras[moduleKey].CheckUuid = pid;
            cameras[moduleKey].IsNg = isNG;
            Logout($"SetCheckResultVaule___成功，ID:{moduleKey}.");
            return 0;
        }
        /// <summary>
        /// 清除读码报警
        /// </summary>
        public void ClearQrCodeAlarm()
        {
            readCodeTimeOut = 0;
        }
        public bool CanGrab()
        {
            if (IsDetect)
            {
                if (autoStep == AutoStepE.WaiteGrabCommand)
                {
                    return true;
                }
            }
            else
            {
                if (autoStep == AutoStepE.Wait && runTaskStep == ModuleTaskStateE.Idle)
                {
                    return true;
                }
            }
             return false;
        }
        public bool StartGrab()
        {
            if (CanGrab())
            {
                RecvdGrabCmd = true;
                return true;
            }
            return false;
        }
        public void GetState(ref long state)
        {
            state = 0;

            if (codeReader.IsOpen)
            {
                state |= 1; //
            }
            if (AxisT.IsCheckDone())
            {
                state |= (1 << 1); //
            }
            if (AxisW.IsCheckDone())
            {
                state |= (1 << 2); //
            }

            if (StopCylinder.IsOn())
            {
                state |= (1 << 3); //
            }

            if (PressCylinder.IsOn())
            {
                state |= (1 << 4); //
            }
            if (InputSensor.IsOn())
            {
                state |= (1 << 5); //
            }
            if (DecelSensor.IsOn())
            {
                state |= (1 << 6); //
            }
            if (StopSensor.IsOn())
            {
                state |= (1 << 7); //
            }
            if (OutputSensor.IsOn())
            {
                state |= (1 << 8); //
            }
            if (Smema.DiFrontReady.IsOn())
            {
                state |= (1 << 9); //
            }
            if (Smema.DiAfterReady.IsOn())
            {
                state |= (1 << 10); //
            }
            if (Smema.DoFrontReady.IsTurnOn())
            {
                state |= (1 << 11); //
            }
            if (Smema.DoAfterReady.IsTurnOn())
            {
                state |= (1 << 12); //
            }
            if (Smema.DoCheckReady.IsTurnOn())
            {
                state |= (1 << 13); //
            }
            if (CanGrab())
            {
                state |= (1 << 14); //
            }
        }
        #endregion
    }
}
